package cn.ilikes.tools.nosql.jpa.classloads.resources;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

import org.slf4j.Logger;

import cn.ilikes.tools.logs.Loggerfactory;
import cn.ilikes.tools.nosql.jpa.classloads.ClasspathResourcesException;
import cn.ilikes.tools.nosql.jpa.classloads.URLPathLoadResources;
import cn.ilikes.tools.nosql.jpa.classloads.URLPathLoadResources.ResourcesType;

public abstract class Resources implements IResources {

	private URLPathLoadResources loadedResources;

	public Resources(URLPathLoadResources loadedResources) {
		super();
		this.loadedResources = loadedResources;
	}

	private static Logger logger = Loggerfactory.instance(Resources.class);

	protected void loadJar(String jarFile) {
		//		if (Loggerfactory.isdebug(logger))Loggerfactory.info(logger, "load jar file :  " + jarFile);
		FileInputStream fis = null;
		try {
			fis = new FileInputStream(jarFile);
			loadJar(fis);
		} catch (IOException e) {
			throw new ClasspathResourcesException(e);
		} finally {
			if (fis != null)
				try {
					fis.close();
				} catch (IOException e) {
					throw new ClasspathResourcesException(e);
				}
		}
	}

	/**
	 * Reads the jar file from a specified URL
	 * 
	 * @param url
	 */
	protected void loadJar(URL url) {
		if (Loggerfactory.isdebug(logger))
			Loggerfactory.info(logger, "load url :  " + url.toString());

		InputStream in = null;
		try {
			in = url.openStream();
			loadJar(in);
		} catch (IOException e) {
			throw new ClasspathResourcesException(e);
		} finally {
			if (in != null)
				try {
					in.close();
				} catch (IOException e) {
					throw new ClasspathResourcesException(e);
				}
		}
	}

	/**
	 * Load the jar contents from InputStream
	 * 
	 */
	protected void loadJar(InputStream jarStream) {

		BufferedInputStream bis = null;
		JarInputStream jis = null;

		try {
			bis = new BufferedInputStream(jarStream);
			jis = new JarInputStream(bis);
			JarEntry jarEntry = null;
			while ((jarEntry = jis.getNextJarEntry()) != null) {
				if (jarEntry.isDirectory()) {
					continue;
				}

				saveResourceses(jarEntry.getName(), copyInputStream(jis));
			}
		} catch (IOException e) {
			throw new ClasspathResourcesException(e);
		} catch (NullPointerException e) {
			Loggerfactory.info(logger, "Done loading.");

		} finally {
			if (jis != null)
				try {
					jis.close();
				} catch (IOException e) {
					throw new ClasspathResourcesException(e);
				}

			if (bis != null)
				try {
					bis.close();
				} catch (IOException e) {
					throw new ClasspathResourcesException(e);
				}
		}
	}

	protected void saveResourceses(String resourcesName, byte[] extra) {
		//		if(Loggerfactory.isdebug(logger))Loggerfactory.debug(logger, "  resourcesName  "+resourcesName+"  size : "+extra.length);
		resourcesName = resourcesName.replace("/", ".");
		if (resourcesName.endsWith(".class")) {
			loadedResources.loadedResources(resourcesName, extra, ResourcesType.classes);
		} else {
			loadedResources.loadedResources(resourcesName, extra, ResourcesType.noClasses);
		}
	}

	protected byte[] copyInputStream(InputStream in) throws IOException {

		ByteArrayOutputStream _copy = new ByteArrayOutputStream();
		int read = 0;
		int chunk = 0;
		byte[] data = new byte[256];
		while (-1 != (chunk = in.read(data))) {
			read += data.length;
			_copy.write(data, 0, chunk);
		}
		;
		return _copy.toByteArray();

	}

	protected byte[] readFile(File file) {
		FileInputStream fileInputStream = null;
		try {
			fileInputStream = new FileInputStream(file);
			int length = fileInputStream.available();
			byte[] con = new byte[length];
			fileInputStream.read(con);
			return con;
		} catch (FileNotFoundException e) {
			return null;
		} catch (IOException e) {
			return null;
		} finally {
			if (fileInputStream != null)
				try {
					fileInputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
	}

}
